from typing import List

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from scipy.optimize import curve_fit

from backend.app.app.crud_pub.tb_project_message import get_name_year, page_recovery_read, page_recovery_save, \
    get_all_projname
from backend.app.app.crud_pub.tb_project_forecas import get_lib, add_data, delete_data, modify_data
from backend.app.app.models.effect_pridict.effect_pri import select, save_data, data_x_y, \
    page_recovery_data_read, page_recovery_data_save
from backend.app.app.api.api_v1.user import verify_token_user
from backend.app.app.api.effect_pridict.formula import *

pridict_router = APIRouter(prefix="/pridict", tags=["2.单元方案措施效果预测"])


class data_tiaohe(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    year: int


@pridict_router.post("/fit_t_parm", name="根据调和函数参数拟合")
async def fit_t_parm(data: data_tiaohe, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_tiao(t=l + i + 1, c0=data.parm1, c1=data.parm2))
    R = 0
    for i in range(l):
        y_ = func_tiao(t=i + 1, c0=data.parm1, c1=data.parm2)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp

    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_t", name="调和函数拟合")
async def fit_t(data: data_x_y, verify=Depends(verify_token_user)):
    xdata = data.x_data
    ydata = data.y_data
    try:
        for i in range(len(xdata)):
            xdata[i] = i + 1
        popt, pcov = curve_fit(func_tiao, xdata, ydata)
        y2 = [func_tiao(i, popt[0], popt[1]) for i in xdata]
    except BaseException:
        return {"fit": False, "verify": verify}
    y_pridict = []
    for i in range(data.year):
        temp_x = xdata[len(xdata) - 1] + i + 0.1
        temp = func_tiao(temp_x, popt[0], popt[1])
        y_pridict.append(temp)
    R = 0
    for i in range(len(data.x_data)):
        y_ = func_tiao(i + 1, popt[0], popt[1])
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": y2, "Y_pridict": y_pridict, "R2": R, "parm1": popt[0], "parm2": popt[1], "verify": verify}


class data_s(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    parm3: float
    year: int


@pridict_router.post("/fit_s_parm", name="根据双曲函数参数拟合")
async def fit_s_parm(data: data_s, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_s(t=l + i + 1, c0=data.parm1, c1=data.parm2, c2=data.parm3))
    R = 0
    for i in range(l):
        y_ = func_s(t=i + 1, c0=data.parm1, c1=data.parm2, c2=data.parm3)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_s", name="双曲函数拟合")
async def fit_s(data: data_x_y, verify=Depends(verify_token_user)):
    xdata = data.x_data
    ydata = data.y_data
    try:
        for i in range(len(xdata)):
            xdata[i] = i + 1
        popt, pcov = curve_fit(func_s, xdata, ydata)
        y2 = [func_s(i, popt[0], popt[1], popt[2]) for i in xdata]
    except BaseException:
        return {"fit": False, "verify": verify}
    y_pridict = []
    for i in range(data.year):
        temp_x = xdata[len(xdata) - 1] + i + 0.1
        temp = func_s(temp_x, popt[0], popt[1], popt[2])
        y_pridict.append(temp)
    R = 0
    for i in range(len(data.x_data)):
        y_ = func_s(i + 1, popt[0], popt[1], popt[2])
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": y2, "Y_pridict": y_pridict, "R2": R, "parm1": popt[0], "parm2": popt[1], "parm3": popt[2],
            "verify": verify}


class data_z(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    parm3: float
    year: int


@pridict_router.post("/fit_index_parm", name="根据指数函数参数拟合")
async def fit_index_parm(data: data_z, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func(x=l + i + 1, a=data.parm1, b=data.parm2, c=data.parm3))
    R = 0
    for i in range(l):
        y_ = func(x=i + 1, a=data.parm1, b=data.parm2, c=data.parm3)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_index", name="指数函数拟合")  #
async def fit_index(data: data_x_y, verify=Depends(verify_token_user)):
    xdata = data.x_data
    ydata = data.y_data
    try:
        for i in range(len(xdata)):
            xdata[i] = i + 1
        print(xdata)
        popt, pcov = curve_fit(func, xdata, ydata)
        y2 = [func(i, popt[0], popt[1], popt[2]) for i in xdata]
        y_pridict = []
        for i in range(data.year):
            temp_x = xdata[len(xdata) - 1] + i + 0.1
            temp = func(temp_x, popt[0], popt[1], popt[2])
            y_pridict.append(temp)
        R = 0
        for i in range(len(data.x_data)):
            y_ = func(i + 1, popt[0], popt[1], popt[2])
            temp = (y_ - data.y_data[i]) ** 2
            R += temp
        return {"fit_Y_values": y2, "Y_pridict": y_pridict, "R2": R, "parm1": popt[0], "parm2": popt[1],
                "parm3": popt[2], "verify": verify}
    except Exception:
        return {"fit": False, "verify": verify}


class data_mi(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    parm3: float
    year: int


@pridict_router.post("/fit_mi_parm", name="根据指数函数参数拟合")
async def fit_mi_parm(data: data_mi, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_mi(t=l + i + 1, c0=data.parm1, c1=data.parm2, c2=data.parm3))
    R = 0
    for i in range(l):
        y_ = func_mi(t=i + 1, c0=data.parm1, c1=data.parm2, c2=data.parm3)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_mi", name="幂函数拟合")  #
async def fit_mi(data: data_x_y, verify=Depends(verify_token_user)):
    xdata = data.x_data
    ydata = data.y_data
    try:
        for i in range(len(xdata)):
            xdata[i] = i + 1
        popt, pcov = curve_fit(func_mi, xdata, ydata)
        y2 = [func_mi(i, popt[0], popt[1], popt[2]) for i in xdata]
        y_pridict = []
        for i in range(data.year):
            temp_x = xdata[len(xdata) - 1] + i + 1
            temp = func_mi(temp_x, popt[0], popt[1], popt[2])
            y_pridict.append(temp)
        R = 0
        for i in range(len(data.x_data)):
            y_ = func_mi(i + 1, popt[0], popt[1], popt[2])
            temp = (y_ - data.y_data[i]) ** 2
            R += temp
        return {"fit_Y_values": y2, "Y_pridict": y_pridict, "R2": R, "parm1": popt[0], "parm2": popt[1],
                "parm3": popt[2], "verify": verify}
    except Exception:
        return {"fit": False, "verify": verify}


class data_line(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    year: int


@pridict_router.post("/fit_line_parm", name="根据一次函数参数拟合")
async def fit_line_parm(data: data_line, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_line_1(x=l + i + 1, k=data.parm1, b=data.parm2))
    R = 0
    for i in range(l):
        y_ = func_line_1(x=i + 1, k=data.parm1, b=data.parm2)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_Line", name="1次线性拟合")
async def fit_Line(data: data_x_y, verify=Depends(verify_token_user)):
    # ,"parm1":popt[0],"parm2":popt[1],"parm3":popt[2]
    x_ = np.array(data.x_data)
    y_ = np.array(data.y_data)
    try:
        f1 = np.polyfit(x_, y_, 1)
        print(f1)
        yvals = np.polyval(f1, x_)
    except Exception:
        return {"fit": False, "verify": verify}
    x_pridict = []
    for i in range(data.year):
        x_pridict.append(x_[len(x_) - 1] + i + 1)
    y_pridict = np.polyval(f1, x_pridict)
    y_pridict = list(y_pridict)
    yvals = list(yvals)
    R = 0
    for i in range(len(data.x_data)):
        y_ = func_line_1(x=i + 1, k=f1[0], b=f1[1])
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": yvals, "Y_pridict": y_pridict, "R2": R, "parm1": f1[0], "parm2": f1[1], "verify": verify}


class data_line2(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    parm3: float
    year: int


@pridict_router.post("/fit_line2_parm", name="根据二次函数参数拟合")
async def fit_line2_parm(data: data_line2, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_line_2(x=l + i + 1, a=data.parm1, b=data.parm2, c=data.parm3))
    R = 0
    for i in range(l):
        y_ = func_line_2(x=i + 1, a=data.parm1, b=data.parm2, c=data.parm3)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_Line_2", name="2次线性拟合")  # , "verify": verify
async def fit_Line_2(data: data_x_y, verify=Depends(verify_token_user)):
    x_ = np.array(data.x_data)
    y_ = np.array(data.y_data)
    try:
        f1 = np.polyfit(x_, y_, 2)
        print(f1)
        yvals = np.polyval(f1, x_)
    except Exception:
        return {"fit": False, "verify": verify}
    x_pridict = []
    for i in range(data.year):
        x_pridict.append(x_[len(x_) - 1] + i + 1)
    y_pridict = np.polyval(f1, x_pridict)
    y_pridict = list(y_pridict)
    yvals = list(yvals)
    R = 0
    for i in range(len(data.x_data)):
        y_ = func_line_2(x=i + 1, a=f1[0], b=f1[1], c=f1[2])
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": yvals, "Y_pridict": y_pridict, "R2": R, "parm1": f1[0], "parm2": f1[1], "parm3": f1[2],
            "verify": verify}


class data_line3(BaseModel):
    x_data: list
    y_data: list
    parm1: float
    parm2: float
    parm3: float
    parm4: float
    year: int


@pridict_router.post("/fit_line3_parm", name="根据三次函数参数拟合")
async def fit_line3_parm(data: data_line3, verify=Depends(verify_token_user)):
    re = []
    l = len(data.x_data)
    for i in range(data.year):
        re.append(func_line_3(x=l + i + 1, a=data.parm1, b=data.parm2, c=data.parm3, d=data.parm4))
    R = 0
    for i in range(l):
        y_ = func_line_3(x=i + 1, a=data.parm1, b=data.parm2, c=data.parm3, d=data.parm4)
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": re, "R2": R, "verify": verify}


@pridict_router.post("/fit_Line_3", name="3次线性拟合")
async def fit_Line_3(data: data_x_y, verify=Depends(verify_token_user)):  #
    x_ = np.array(data.x_data)
    y_ = np.array(data.y_data)
    try:
        f1 = np.polyfit(x_, y_, 3)
        yvals = np.polyval(f1, x_)
    except Exception:
        return {"fit": False, "verify": verify}
    x_pridict = []
    for i in range(data.year):
        x_pridict.append(x_[len(x_) - 1] + i + 1)
    y_pridict = np.polyval(f1, x_pridict)
    y_pridict = list(y_pridict)
    yvals = list(yvals)
    R = 0
    for i in range(len(data.x_data)):
        y_ = func_line_3(x=i + 1, a=f1[0], b=f1[1], c=f1[2], d=f1[3])
        temp = (y_ - data.y_data[i]) ** 2
        R += temp
    return {"fit_Y_values": yvals, "Y_pridict": y_pridict, "R2": R, "parm1": f1[0], "parm2": f1[1], "parm3": f1[2],
            "parm4": f1[3], "verify": verify}


@pridict_router.post("/save_lib", name="存库")
async def save_lib(trans_data: save_data, verify=Depends(verify_token_user)):
    a = False
    b = False
    c = False
    for i in trans_data.add:
        if i:
            a = add_data(data=i)
    for j in trans_data.delete:
        if j:
            b = delete_data(data=j)
    for k in trans_data.modify:
        if k:
            c = modify_data(data=k)

    return {"add": a, "delete": b, "modify": c, "verify": verify}


@pridict_router.post("/read_lib", name="读库")
async def read_lib(data: select, verify=Depends(verify_token_user)):
    re = get_lib(name=data.d_name, type=data.type_, start=data.start_year, end=data.end_year)

    return {"result": re, "verify": verify}


@pridict_router.post("/read_name_year", name="读取名称，类别，起始结束年份")
async def read_n_y(verify=Depends(verify_token_user)):
    data = get_name_year()
    name = []
    type_ = []
    start_year = []
    end_year = []
    for i in data:
        if i[0]:
            if i[0] not in name:
                name.append(i[0])
        if i[1]:
            if i[1] not in type_:
                type_.append(i[1])
        if i[2]:
            if i[2] not in start_year:
                start_year.append(i[2])
        if i[3]:
            if i[3] not in end_year:
                end_year.append(i[3])
    return {"name": name, "type": type_, "start_year": start_year, "end_year": end_year, "verify": verify}


@pridict_router.post("/read_page_recovery", name="读取页面恢复")
async def read_page_recovery(page_recovery: page_recovery_data_read, verify=Depends(verify_token_user)):
    result = page_recovery_read(page_recovery.userid, page_recovery.projid)
    return {"result": result, "verify": verify}


@pridict_router.post("/save_page_recovery", name="存储页面恢复")
async def save_page_recovery(page_recovery_list: List[page_recovery_data_save], verify=Depends(verify_token_user)):
    result = page_recovery_save(page_recovery_list)
    return {"result": result, "verify": verify}


@pridict_router.post("/get_all_proj_name", name="获取所有的方案名称")
async def get_all_proj_name(verify=Depends(verify_token_user)):
    result = get_all_projname()
    return {"result": result, "verify": verify}
